#!/bin/bash
#Author: YangYi
#Date: 2025-05-10
#Version: v1
#Content 一键诊断、处置原子能力,应用可用性测试.
#1.输入服务名（deployment）获取所有pod清单
#2.pod做访问测试（测试方式作为入参输入）
#3.依赖要求：jq、curl、timeout
#4.创建测试:    kubectl create deployment nginx  --image=hub.paas/base/nginx:1.13.10  && kubectl expose deployment nginx  --type=NodePort --port=80 --target-port=80 --name=nginx

#Date: 2025-05-20
#Content: 
#1. 增加七层探测函数，支持GET请求,args$3
#2. 增加禁止对系统级名称空间资源进行操作
#


# ---------------------------初始化全局变量----------------------------

# 检查参数是否传入
if [ -z "$1" ]; then
    echo "错误：请输入要检查的名称空间(namespces)"
    exit 1
fi

if [ -z "$2" ]; then
    echo "错误：请输入要检查的服务名(deploy)"
    exit 1
fi

if [ -z "$3" ]; then
    echo "输入接口参数可进行服务七层探测,只支持GET请求!"
fi

NAMESPACE=$1
DEPLOYMENT=$2
INTERFACE=$3

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m'

# 从kubeconfig获取token
CURRENT_CONTEXT=$(kubectl config current-context)
USER=$(kubectl config view -o jsonpath="{.contexts[?(@.name == '${CURRENT_CONTEXT}')].context.user}")
TOKEN=$(kubectl describe secret $(kubectl get secret | grep ^default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t' | tr -d ' ')
KUBECONFIG="/root/.kube/config"
APISERVER=$(kubectl config view --minify --flatten --kubeconfig="${KUBECONFIG}" | grep server | cut -d '/' -f3)

# 不允许操作资源
#protected_namespaces=("custom-metrics" "monitoring" "kube-system" "kube-public" "default")
protected_namespaces=("kube-public")


# ----------------------------功能模块函数-----------------------------

# 检查必要工具是否存在
check_dependencies() {
    if ! command -v nc &> /dev/null; then
        echo "错误:需要安装netcat工具（nc命令）"
        exit 1
    fi
    if ! command -v kubectl &> /dev/null; then
        echo "错误:需要安装kubectl命令行工具"
        exit 1
    fi
    if ! command -v jq &> /dev/null; then
        echo "错误:需要安装jq命令行工具"
        exit 1
    fi
}

# 验证命名空间是否存在
check_namespace() {
    response=$(curl -sSk -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "http://$APISERVER/api/v1/namespaces/$NAMESPACE")
    [ "$response" -ne 200 ] && echo "Error: Namespace $NAMESPACE not found" && exit 1
}

# 验证Deployment是否存在
check_deployment() {
    response=$(curl -sSk -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$APISERVER/apis/apps/v1/namespaces/$NAMESPACE/deployments/$DEPLOYMENT")
    [ "$response" -ne 200 ] && echo "Error: Deployment $DEPLOYMENT not found in $NAMESPACE" && exit 1
}


# 查询Deployment信息
deploy_info=$(curl -s -H "Authorization: Bearer $TOKEN" "$APISERVER/apis/apps/v1/namespaces/$NAMESPACE/deployments/$DEPLOYMENT")
if [[ $? -ne 0 ]]; then
    echo "错误：无法连接Kubernetes API服务器"
    exit 1
fi

if echo "$deploy_info" | grep 'NotFound' >/dev/null; then
    echo "错误：未找到指定的Deployment"
    exit 1
fi

# 提取标签选择器
selector=$(echo "$deploy_info" | jq -r '.spec.selector.matchLabels | to_entries | map("\(.key)=\(.value)") | join(",")')
if [[ -z "$selector" ]]; then
    echo "错误：无法解析Deployment的标签选择器"
    exit 1
fi

# 执行四层探测函数
probe_service() {
    local ns=$1
    local ip=$2
    local port=$3
    local host=$4
    local interval=1
    local success_count=0
    local total_attempts=3
    local required_success=1
    
    echo "服务:$ns, IP:$ip, 端口:$port, 所在节点:$host, ($total_attempts 次尝试，间隔$interval 秒)"
    echo "开始端口探测:"
 
    # 执行四层探测
    for ((i=1; i<=$total_attempts; i++)); do
        # 使用nc进行TCP端口探测（超时1秒）
        if nc -zvw1 "$ip" "$port" &>/dev/null; then
            echo "探测端口$i: 成功"
            ((success_count++))
        else
            echo "探测端口$i: 失败"
        fi
 
        # 非最后一次尝试时等待3秒
        [[ $i -lt $total_attempts ]] && sleep $interval
    done
 
    # 判断结果
    if [[ $success_count -ge $required_success ]]; then
        echo "端口正常（$success_count/$total_attempts 次成功）"
        #echo "${GREEN}$ns 运行正常($success_count/$total_attempts 次成功)${NC}"
        return 0
    else
        echo "端口异常（$success_count/$total_attempts 次成功）"
        #echo "${RED}$ns 异常($success_count/$total_attempts 次成功)${NC}"
        return 1
    fi
}

# 执行七层探测函数
interface_detection() {
    local ns=$1
    local ip=$2
    local port=$3
    local host=$4
    local interface=$5
    local interval=1
    local success_count=0
    local total_attempts=3
    local required_success=1

    echo "开始接口探测"

    # 执行七层探测
    for ((i=1; i<=$total_attempts; i++)); do
     
        # 获取curl的退出状态码和HTTP状态码
        response=$(curl -s --max-time 1 -w "%{http_code}" -o /dev/null http://$ip:$port/$interface)
        exit_code=$?
     
        # 确保curl执行成功
        if [ $exit_code -eq 0 ]; then 

        # 验证HTTP状态码是否为数字且等于200
        if [[ "$response" =~ ^[0-9]{3}$ ]] && [ "$response" -eq 200 ]; then
            echo "探测接口$i: 成功"
            ((success_count++))
        else
            echo "探测接口$i: 失败"
        fi
    else
        # 处理curl执行失败的情况（如网络不可达）
        echo "异常 连接失败"
    fi
    
    sleep 1  # 间隔1秒

        # 非最后一次尝试时等待3秒
        [[ $i -lt $total_attempts ]] && sleep $interval
    done
    
    # 判断结果
    if [[ $success_count -ge $required_success ]]; then
        echo "接口正常（$success_count/$total_attempts 次成功）"
        #echo "${GREEN}$ns 运行正常($success_count/$total_attempts 次成功)${NC}"
        return 0
    else
        echo "接口异常（$success_count/$total_attempts 次成功）"
        #echo "${RED}$ns 异常($success_count/$total_attempts 次成功)${NC}"
        return 1
    fi

}

# 主逻辑
main() {
   
   if [[ " ${protected_namespaces[@]} " =~ " ${NAMESPACE} " ]]; then
     echo "错误:禁止对 $NAMESPACE 命名空间进行操作!"
     exit 1 
   fi

    check_dependencies
    check_namespace
    check_deployment
    
    # 获取Deployment关联的Pod列表
    #PODS=$(curl -sSk -H "Authorization: Bearer $TOKEN" "$APISERVER/api/v1/namespaces/$NAMESPACE/pods?labelSelector=app%$DEPLOYMENT")
    PODS=$(curl -s -H "Authorization: Bearer $TOKEN" "$APISERVER/api/v1/namespaces/$NAMESPACE/pods?labelSelector=$selector")
    
    # 提取异常Pod信息
    echo "$PODS" | jq -c '.items[]' | while read -r pod; do
        
        #phase=$(echo $pod | jq -r '.status.phase')
        #[ "$phase" != "Running" ] || continue
        
        pod_name=$(echo $pod | jq -r '.metadata.name')
        pod_ip=$(echo $pod | jq -r '.status.podIP')
        [ -z "$pod_ip" ] && continue

        # 获取关联Service端口
        SERVICE_INFO=$(curl -sSk -H "Authorization: Bearer $TOKEN" "$APISERVER/api/v1/namespaces/$NAMESPACE/services/$DEPLOYMENT")
        pod_port=$(echo $SERVICE_INFO | jq -r '.spec.ports[0].port') 
        host_ip=$(echo $pod | jq -r '.status.hostIP')
       
        # 执行探测
        probe_service "$pod_name" "$pod_ip" "$pod_port" "$host_ip"
        if [ -n "$INTERFACE" ]; then
           interface_detection "$pod_name" "$pod_ip" "$pod_port" "$host_ip" "$INTERFACE"
        fi
    done
}

main




